"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TSXComplianceChecker = void 0;
const parser_1 = require("@babel/parser");
const traverse_1 = __importDefault(require("@babel/traverse"));
const t = __importStar(require("@babel/types"));
class TSXComplianceChecker {
    /**
     * 使用 AST 检查 TSX 规范
     */
    static checkTSXCompliance(content, filename) {
        const issues = [];
        try {
            // 使用 Babel 解析 TSX 代码
            const ast = (0, parser_1.parse)(content, {
                sourceType: 'module',
                plugins: ['jsx', 'typescript', 'decorators-legacy', 'classProperties'],
                errorRecovery: true,
            });
            // 遍历 AST 进行检查
            (0, traverse_1.default)(ast, {
                // 检查变量声明
                VariableDeclarator(path) {
                    TSXComplianceChecker.checkVariableDeclaration(path, content, issues);
                },
                // 检查方法定义
                ClassMethod(path) {
                    TSXComplianceChecker.checkMethodDefinition(path, content, issues);
                },
                // 检查 JSX 使用
                JSXElement(path) {
                    TSXComplianceChecker.checkJSXUsage(path, content, issues);
                },
                // 检查类型注解
                TSTypeAnnotation(path) {
                    TSXComplianceChecker.checkTypeAnnotation(path, content, issues);
                },
            });
            // 检查必需的结构
            this.checkRequiredStructures(ast, content, issues);
        }
        catch (error) {
            issues.push({
                type: 'error',
                code: 'PARSE_ERROR',
                message: `代码解析失败: ${error.message}`,
                suggestion: '检查代码语法是否正确',
            });
        }
        return {
            isCompliant: issues.filter((issue) => issue.type === 'error').length === 0,
            issues,
        };
    }
    /**
     * 检查变量声明
     */
    static checkVariableDeclaration(path, content, issues) {
        const node = path.node;
        // 检查是否在 render 方法中
        const renderMethod = path.findParent((p) => p.isClassMethod() && t.isIdentifier(p.node.key) && p.node.key.name === 'render');
        if (!renderMethod)
            return;
        // 检查是否在事件处理函数中
        const isInEventHandler = this.isInEventHandler(path);
        if (isInEventHandler)
            return;
        // 检查是否在非 JSX 返回的回调函数中
        const isInNonJSXCallback = this.isInNonJSXCallback(path);
        if (isInNonJSXCallback)
            return;
        // 检查是否在返回 JSX 的回调函数中（如 .map()）
        const isInJSXCallback = this.isInJSXCallback(path);
        if (isInJSXCallback) {
            // 这种情况需要报错
            const { line, column } = this.getLocation(path, content);
            const snippet = this.extractCodeSnippet(content, line);
            issues.push({
                type: 'error',
                code: 'CALLBACK_VARIABLE_DECLARATION',
                message: '返回 JSX 的回调函数中不能包含变量声明',
                suggestion: '将变量声明移到回调函数外部，或使用内联表达式',
                line,
                column,
                codeSnippet: snippet.snippet,
                snippetStartLine: snippet.startLine,
                snippetEndLine: snippet.endLine,
            });
            return;
        }
        // 其他在 render 方法中的变量声明都是错误的
        const { line, column } = this.getLocation(path, content);
        const snippet = this.extractCodeSnippet(content, line);
        issues.push({
            type: 'error',
            code: 'RENDER_VARIABLE_DECLARATION',
            message: 'render() 方法中不能包含变量声明',
            suggestion: '移除所有 const/let/var 声明，直接使用 this.state.xxx',
            line,
            column,
            codeSnippet: snippet.snippet,
            snippetStartLine: snippet.startLine,
            snippetEndLine: snippet.endLine,
        });
    }
    /**
     * 检查是否在事件处理函数中
     */
    static isInEventHandler(path) {
        // 查找父级 JSX 属性
        const jsxAttribute = path.findParent((p) => p.isJSXAttribute());
        if (jsxAttribute && t.isJSXIdentifier(jsxAttribute.node.name)) {
            const attrName = jsxAttribute.node.name.name;
            // 检查是否是事件处理属性（onXxx）
            if (/^on[A-Z]/.test(attrName)) {
                return true;
            }
        }
        // 检查是否在 addEventListener 回调中
        const callExpression = path.findParent((p) => p.isCallExpression());
        if (callExpression && t.isMemberExpression(callExpression.node.callee)) {
            const memberExpr = callExpression.node.callee;
            if (t.isIdentifier(memberExpr.property) && memberExpr.property.name === 'addEventListener') {
                return true;
            }
        }
        return false;
    }
    /**
     * 检查是否在非 JSX 返回的回调函数中
     */
    static isInNonJSXCallback(path) {
        // 查找父级函数
        const parentFunction = path.findParent((p) => p.isArrowFunctionExpression() || p.isFunctionExpression());
        if (!parentFunction)
            return false;
        // 检查是否在 JSX 属性回调中（如 beforeUpload, customRequest 等）
        const jsxAttribute = parentFunction.findParent((p) => p.isJSXAttribute());
        if (jsxAttribute && t.isJSXIdentifier(jsxAttribute.node.name)) {
            const attrName = jsxAttribute.node.name.name;
            // 这些属性通常不返回 JSX
            const nonJSXAttributes = [
                'beforeUpload',
                'customRequest',
                'onChange',
                'onFinish',
                'onSubmit',
                'onSuccess',
                'onError',
                'onProgress',
                'request',
                'dataHandler',
            ];
            if (nonJSXAttributes.includes(attrName)) {
                return true;
            }
        }
        // 检查函数是否返回 JSX
        const returnsJSX = this.functionReturnsJSX(parentFunction);
        // 如果不返回 JSX，则认为是非 JSX 回调
        return !returnsJSX;
    }
    /**
     * 检查是否在返回 JSX 的回调函数中
     */
    static isInJSXCallback(path) {
        // 查找父级函数
        const parentFunction = path.findParent((p) => p.isArrowFunctionExpression() || p.isFunctionExpression());
        if (!parentFunction)
            return false;
        // 检查函数是否返回 JSX
        return this.functionReturnsJSX(parentFunction);
    }
    /**
     * 检查函数是否返回 JSX
     */
    static functionReturnsJSX(functionPath) {
        let returnsJSX = false;
        functionPath.traverse({
            ReturnStatement(path) {
                if (path.node.argument && t.isJSXElement(path.node.argument)) {
                    returnsJSX = true;
                }
            },
            JSXElement(path) {
                // 如果函数体直接包含 JSX（箭头函数的隐式返回）
                if (path.parent === functionPath.node.body) {
                    returnsJSX = true;
                }
            },
        });
        return returnsJSX;
    }
    /**
     * 检查方法定义
     */
    static checkMethodDefinition(path, content, issues) {
        const node = path.node;
        // 跳过 render 方法和渲染相关方法
        if (t.isIdentifier(node.key)) {
            const methodName = node.key.name;
            const renderMethods = [
                'render',
                'renderItem',
                'renderContent',
                'renderHeader',
                'renderFooter',
            ];
            if (renderMethods.includes(methodName))
                return;
            // 检查方法中是否包含 JSX
            let containsJSX = false;
            path.traverse({
                JSXElement() {
                    containsJSX = true;
                },
            });
            if (containsJSX) {
                const { line, column } = this.getLocation(path, content);
                const snippet = this.extractCodeSnippet(content, line);
                issues.push({
                    type: 'error',
                    code: 'METHOD_CONTAINS_JSX',
                    message: `方法 ${methodName} 不能包含 JSX 语法`,
                    suggestion: '只有 render() 方法可以包含 JSX，其他方法只处理逻辑',
                    line,
                    column,
                    codeSnippet: snippet.snippet,
                    snippetStartLine: snippet.startLine,
                    snippetEndLine: snippet.endLine,
                });
            }
        }
    }
    /**
     * 检查 JSX 使用
     */
    static checkJSXUsage(path, content, issues) {
        // 暂时不实现，专注于变量声明检查
    }
    /**
     * 检查类型注解
     */
    static checkTypeAnnotation(path, content, issues) {
        // 暂时不实现，专注于变量声明检查
    }
    /**
     * 检查必需的结构
     */
    static checkRequiredStructures(ast, content, issues) {
        // 这里可以添加对必需结构的检查
        // 如 IProps, IState, Document 类等
    }
    /**
     * 获取节点在源码中的位置
     */
    static getLocation(path, content) {
        const loc = path.node.loc;
        return {
            line: loc ? loc.start.line : 1,
            column: loc ? loc.start.column : 0,
        };
    }
    /**
     * 提取代码片段
     */
    static extractCodeSnippet(content, lineNumber, contextLines = 3) {
        const lines = content.split('\n');
        const startLine = Math.max(1, lineNumber - contextLines);
        const endLine = Math.min(lines.length, lineNumber + contextLines);
        const snippetLines = [];
        for (let i = startLine; i <= endLine; i++) {
            const line = lines[i - 1] || '';
            const prefix = i === lineNumber ? '>>> ' : '    ';
            snippetLines.push(`${prefix}${i.toString().padStart(3)}: ${line}`);
        }
        return {
            snippet: snippetLines.join('\n'),
            startLine,
            endLine,
        };
    }
    /**
     * 生成检查报告
     */
    static generateReport(result, filename) {
        const { isCompliant, issues } = result;
        let report = '=== TSX 规范检查报告 ===\n';
        report += `文件: ${filename}\n`;
        if (isCompliant) {
            report += '✅ 检查通过：文件符合 TSX 规范\n';
        }
        else {
            const errorCount = issues.filter((issue) => issue.type === 'error').length;
            report += `❌ 检查失败：发现 ${errorCount} 个错误\n\n`;
            report += '--- 问题详情 ---\n';
            issues.forEach((issue, index) => {
                const icon = issue.type === 'error' ? '❌' : '⚠️';
                report += `${index + 1}. ${icon} [${issue.code}] ${issue.message}\n`;
                if (issue.line) {
                    report += `   📍 位置: 第 ${issue.line} 行\n`;
                }
                report += `   💡 建议: ${issue.suggestion}\n`;
                if (issue.codeSnippet) {
                    report += `   📝 代码片段:\n${issue.codeSnippet}\n`;
                }
                report += '\n';
            });
        }
        return report;
    }
}
exports.TSXComplianceChecker = TSXComplianceChecker;
